package org.jinghouyu.caculator.engine.node;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jinghouyu.caculator.engine.Expression;
import org.jinghouyu.caculator.engine.ExpressionContext;
import org.jinghouyu.caculator.engine.ExpressionException;
import org.jinghouyu.caculator.engine.expression.FunctionExpression;
import org.jinghouyu.caculator.engine.expression.function.FunctionException;
import org.jinghouyu.caculator.engine.expression.function.RandomFunction;

/**
 * 函数表达式节点
 * @author liujingyu
 *
 */
public class FunctionNode implements ParsableNode {

	private String expression;
	
	public FunctionNode(String expression) {
		this.expression = expression.trim();
	}
	
	public static boolean isFunction(String expression) {
		int index = expression.indexOf("(");
		if(index <= 0) return false;
		String name = expression.substring(0, index);
		//是一个函数
		//是否符合函数定义规范
		char c = name.charAt(0);
		if(c >= '0' && c <= '9') {
			throw new FunctionException("函数名称不能以数字开头：" + name);
		}
		return true;
	}

	private static final Map<String, Class<? extends FunctionExpression>> mapping = new HashMap<>();
	
	static {
		mapping.put("random", RandomFunction.class);
	}
	
	private static FunctionExpression newExpression(String name, ExpressionContext context) {
		name = name.toLowerCase().trim();
		Class<? extends FunctionExpression> clazz = context.getFunctionExpression(name) == null ? mapping.get(name) : context.getFunctionExpression(name);
		if(clazz == null) return null;
		try {
			Constructor<? extends FunctionExpression> c = clazz.getConstructor(new Class[]{String.class});
			return c.newInstance(name);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public Expression parse(ExpressionContext context) {
		int index = expression.indexOf("(");
		String name = expression.substring(0, index).toLowerCase();
		String value = expression.substring(index + 1, expression.length() - 1);
		FunctionExpression expression = newExpression(name, context);
		if(expression == null) throw new ExpressionException("不支持函数：" + this.expression);
		List<String> subExpressions = new ArrayList<>();
		int kuoCount = 0;
		StringBuilder sb = new StringBuilder();
		for(int i = 0; i < value.length(); i++) {
			char c = value.charAt(i);
			if(c == ',' && kuoCount == 0) { //不是括号里面的逗号
				subExpressions.add(sb.toString());
				sb = new StringBuilder();
			} else {
				sb.append(c);
			}
			if(c == '(') {
				kuoCount++;
			}
			if(c == ')') {
				kuoCount--;
			}
		}
		if(sb.length() > 0) {
			subExpressions.add(sb.toString());
		}
		for(String subExpression : subExpressions) {
			expression.addSubExpression(NodeParser.parse(subExpression, context));
		}
		return expression;
	}
}